/**
 * Zap font character definitions
 * (C) Nettle developers 2000-2001
 *
 * $Id: chardefn,v 1.16 2004/04/02 06:31:59 archifishal Exp $
 */

#include "generic.h"
#include "globals.h"

#include "chardefn.h"
#include "misc.h"
#include "zapredraw.h"

/* Define Zap graphics characters */


static void copypair (char *area, int step, int height,
                      const char *base, char upper, char lower)
{
  int x, y;
  const char *ptr = base + upper * step * height;
  for (y = 0; y < height; y++)
  {
    memcpy (area, ptr, step);
    if ((height & 1) && y == height / 2)
      ptr = base + lower * step * height;
    else
      ptr += step;
    for (x = step - 1; x >= 0; x--)
      area[x] |= ptr[x];
    if ((height & 1) == 0 && y == (height - 1) / 2)
      ptr = base + lower * step * height;
    else
      ptr += step;
    area += step;
  }
}


static void make_underline (char *area, int step, int height)
{
  char pixels[8] = {0}; /* hmm, trouble if the font is > 64 pixels wide... */
  int x;

  area += step * height;

  while (--height > 1)
  {
    area -= step;
    for (x = step - 1; x >= 0; --x)
    {
      area[x >> 3] |= area[(x >> 3) - 2 * step] & ~pixels[x >> 3];
      pixels[x >> 3] |= area[x >> 3];
    }
  }
}


void define_zap_chars(int *int_area, int char_size, int width, int height)
{
  int loop;
  int step=char_size/height;
  char *area=(char *) int_area;
  const char *base = area;
  /* define characters */
  area += 0x100 * char_size;

  /* initialise extra character area (chars 0x100-<end>) to 0 */
  memset (area, 0, EXTRA_ZAP_CHARS * char_size);

  /*	Active Cursor	0x100 */
  switch (cursor_type)
  {
    case cursor_solid:
      /* filled rectangle */
      memset (area, 0xff, char_size);
      break;

    case cursor_underline:
      /* Bottom lines of the cursor */
      {
        int lines = (height+4)/8;
        /* 8 pixels  -> 1 line cursor
           12 pixels -> 2 line cursor
           16 pixels -> 2 line cursor
           20 pixels -> 3 line cursor */
        for (loop = 0; loop < step*lines; loop++)
          area[char_size - loop - 1] = 0xff;
      }
  }
  area += char_size;

  /*	Inactive Cursor	0x101 */
  switch (cursor_type)
  {
    case cursor_solid:
      /* unfilled rectangle */
      for (loop = 0; loop < step; loop++)
        area[char_size - loop - 1] = area[loop] = 0xFF;
      if (step == 1)
        for (loop = step; loop < char_size - step; loop += step)
          area[loop] = 1 | 1 << (width - 1);
      else
        for (loop = step; loop < char_size - step; loop += step)
        {
          area[loop] = 1;
          area[loop + step - 1] = 1 << ((width - 1) & 7);
        }
      break;

    case cursor_underline:
      /* Bottom lines of the cursor as a dither pattern */
      {
        int lines = (height+4)/8;
        char *areaend = &area[char_size - 1];
        /* 8 pixels  -> 1 line cursor
           12 pixels -> 2 line cursor
           16 pixels -> 2 line cursor
           20 pixels -> 3 line cursor */
        while (lines-->0)
        {
          for (loop = 0; loop < step; loop++)
            areaend[- loop] = (lines&1) ? 0xAA : 0x55;
          areaend-=step;
        }
      }
      break;
  }
  area+=char_size;

  /*	Diamond		0x102 */
  {
    int scale = (height >= width * 2) ? 2 : 1;
    int pix1 = (MIN (height, width) - 1) / 2;
    int pix2 = pix1;
    char *ptr = area + (height >> 1) * step;
    while (pix1 >= 0)
    {
      int loop2;
      char *ptr2 = ptr - pix1 * step * scale;
      /* top half */
      for (loop2 = pix1; loop2 <= pix2; loop2++)
        ptr2[loop2 / 8] |= 1 << (loop2 & 7);
      if (scale == 2)
      {
        memcpy (ptr2 - step, ptr2, step); /*duplicate*/
        memmove (ptr + pix1 * step * scale - step, ptr2 - step, step * 2); /*mirror*/
      }
      else
        memcpy (ptr + pix1 * step * scale, ptr2, step); /*mirror*/
      pix1--;
      pix2++;
    }
  }
  area+=char_size;

  /*	Checkerboard	0x103 */
  {
    char fill = 0xAA;
    for (loop = 0; loop < char_size; loop += step)
    {
      memset (area + loop, fill, step);
      fill = ~fill;
    }
  }
  area+=char_size;

  /*	H topleft/T bottomright	0x104 */
  copypair (area, step, height, base, 'H', 'T');
  area+=char_size;

  /*	F topleft/F bottomright	0x105 */
  copypair (area, step, height, base, 'F', 'F');
  area+=char_size;

  /*	C topleft/R bottomright	0x106 */
  copypair (area, step, height, base, 'C', 'R');
  area+=char_size;

  /*	L topleft/F bottomright	0x107 */
  copypair (area, step, height, base, 'L', 'F');
  area+=char_size;

  /*	N topleft/L bottomright	0x108 */
  copypair (area, step, height, base, 'N', 'L');
  area+=char_size;

  /*	V topleft/T bottomright	0x109 */
  copypair (area, step, height, base, 'V', 'T');
  area+=char_size;

  /*	_| (bottomright of box)	0x10A */
  for (loop=0; loop<(char_size/2); loop+=step)
    area[loop + (width / 16)] = 1 << (width / 2 & 7);
  for (loop = 0; loop <= width / 2; loop++)
    area[step * (height >> 1) + loop / 8] |= 1 << (loop & 7);
  area+=char_size;

  /*	-, (topright of box)	0x10B */
  for (loop = char_size - step; loop > (char_size/2); loop-=step)
    area[loop + (width / 16)] = 1 << (width / 2 & 7);
  for (loop = 0; loop <= width / 2; loop++)
    area[step * (height >> 1) + loop / 8] |= 1 << (loop & 7);
  area+=char_size;

  /*	,- (topleft of box)	0x10C */
  for (loop = char_size - step; loop > (char_size/2); loop-=step)
    area[loop + (width / 16)] = 1 << (width / 2 & 7);
  for (loop = width / 2; loop < width; loop++)
    area[step * (height >> 1) + loop / 8] |= 1 << (loop & 7);
  area+=char_size;

  /*	|_ (bottomleft of box)	0x10D */
  for (loop=0; loop<(char_size/2); loop+=step)
    area[loop + (width / 16)] = 1 << (width / 2 & 7);
  for (loop = width / 2; loop < width; loop++)
    area[step * (height >> 1) + loop / 8] |= 1 << (loop & 7);
  area+=char_size;

  /*	-|- (crossing lines)	0x10E */
  for (loop=0; loop<char_size; loop+=step)
    area[loop + (width / 16)] = 1 << (width / 2 & 7);
  memset (area + step * (height >> 1), 0xFF, step);
  area+=char_size;

  /*	Horiz line - scan 1	0x10F */
  memset (area, 0xFF, step);
  area+=char_size;

  /*	Scan 3			0x110 */
  memset (area + step * (int) (height * 3 / 10), 0xFF, step);
  area+=char_size;

  /*	Scan 5			0x111 */
  memset (area + step * (int) (height * 5 / 10), 0xFF, step);
  area+=char_size;

  /*	Scan 7			0x112 */
  memset (area + step * (int) (height * 7 / 10), 0xFF, step);
  area+=char_size;

  /*	Scan 9			0x113 */
  memset (area + step * (int) (height * 9 / 10), 0xFF, step);
  area+=char_size;

  /*	Left T |-		0x114 */
  for (loop=0; loop<char_size; loop+=step)
    area[loop + (width / 16)] = 1 << (width / 2 & 7);
  for (loop = width / 2; loop < width; loop++)
    area[step * (height >> 1) + loop / 8] |= 1 << (loop & 7);
  area+=char_size;

  /*	Right T -|	0x115 */
  for (loop=0; loop<char_size; loop+=step)
    area[loop + (width / 16)] = 1 << (width / 2 & 7);
  for (loop = 0; loop < width / 2; loop++)
    area[step * (height >> 1) + loop / 8] |= 1 << (loop & 7);
  area+=char_size;

  /*	Bottom T _|_	0x116 */
  for (loop = 0; loop < (char_size/2); loop+=step)
    area[loop + (width / 16)] = 1 << (width / 2 & 7);
  memset (area + step * (height >> 1), 0xFF, step);
  area+=char_size;

  /*	Top T	T	0x117 */
  for (loop = char_size - step; loop > (char_size/2); loop-=step)
    area[loop + (width / 16)] = 1 << (width / 2 & 7);
  memset (area + step * (height >> 1), 0xFF, step);
  area+=char_size;

  /*    Vertical bar |   0x118 */
  for (loop = 0; loop < char_size; loop+=step)
    area[loop + (width / 16)] = 1 << (width / 2 & 7);
  area+=char_size;

  /*	<=	0x119 */
  memcpy (area, base + '<' * char_size, char_size);
  make_underline (area, step, height);
  area+=char_size;

  /*	>=	0x11A */
  memcpy (area, base + '>' * char_size, char_size);
  make_underline (area, step, height);
  area+=char_size;

  /*	PI	0x11B */
  {
    int pix1 = (width <= 8) ? 1 : 2;
    int pix2 = width - 2 - (width > 8);
    char *ptr = area + (height * 3 / 8) * step;
    for (loop = pix1; loop <= pix2; loop++)
      ptr[loop / 8] |= 1 << (loop & 7);
    pix1 += (width <= 8) ? 1 : 2;
    pix2 -= (width <= 8) ? 1 : 2;
    if (pix2 == pix1 + 1)
      pix2 += 1;
    for (loop = (height * 3 / 8) * step; loop <= (height * 7 / 8) * step; loop++)
    {
      ptr[pix1 / 8] |= 1 << (pix1 & 7);
      ptr[pix2 / 8] |= 1 << (pix2 & 7);
      ptr += step;
    }
  }
  area+=char_size;

  /*	Not equal	0x11C */
  {
    const char *ptr1 = base + '=' * char_size;
    const char *ptr2 = base + '/' * char_size;
    for (loop = char_size - 1; loop >= 0; loop--)
      area[loop] = ptr1[loop] | ptr2[loop];
  }
  area+=char_size;

  /*	Underline	0x11D */
  {
    /* Principle: locate _ and make /any/ pixels that are set span the
       entire row. */
    const char *ptr1 = base + '_' * char_size;
    char *ptr2 = area;
    for (loop = 0; loop<height; loop++)
    {
      int loop2;
      int anyset=0;
      for (loop2 = 0; loop2<step; loop2++)
        anyset|=*ptr1++;

      if (anyset)
      {
        for (loop2 = 0; loop2<step; loop2++)
          *ptr2++=0xff;
      }
      else
        ptr2+=step;
    }
  }
}


void define_zap_undef_chars(int *int_area, int first_char, int last_char,
                            int char_size, int width, int height)
{
  char *area = (char *)int_area;

  if (width == 8 && (height == 8 || height == 16))
  {
    /* System font size - fill in blanks from there */
    int chr = (first_char < 32) ? (last_char - 1) : 31;
    char def[9];
    while (++chr < 0x100)
    {
      if (chr == first_char)
      {
        /* skip the defined characters */
        chr = last_char;
        if (chr >= 0x100)
          break;
      }

      /* undefined character - fill in the definition */
      def[0] = chr;
      _swi (OS_Word, _INR(0,1), 10, def);
      if (height == 8)
        memcpy (area + chr * char_size, def + 1, 8);
      else
      {
        int i;
        char *ptr = area + chr * char_size;
        for (i = 7; i >= 0; --i)
          ptr[i*2 + 1] = ptr[i*2] = def[i + 1];
      }
    }
    if (first_char > 32)
      _swi (ZapRedraw_ReverseBitmaps, _INR(1,3),
            area + 32 * char_size, area + 32 * char_size,
            (first_char - 32) * char_size);
    if (last_char < 256)
      _swi (ZapRedraw_ReverseBitmaps, _INR(1,3),
            area + last_char * char_size, area + last_char * char_size,
            (256 - last_char) * char_size);
  }

  {
    /* Now do the control characters */
    int chr;
    int step=char_size/height;
    for (chr = 0; chr < 32 && chr < first_char; chr++)
      copypair (area + chr * char_size, step, height, area, chr | 64, '-');
  }
}
